package com.lxd.sunso.product.netty.server.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class NettyServer {
    private static final Logger logger = LoggerFactory.getLogger("newLogger");
    @Async
    public void start() {
        //创建BossGroup和WorkerGroup
        //bossGroup只是处理连接请求，真正和客户端业务处理的，交给workerGroup完成，两个都是无线循环
        EventLoopGroup boosGroup = new NioEventLoopGroup(1);
        EventLoopGroup wokerGroup = new NioEventLoopGroup();

        try {
            //创建服务端启动的对象，配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();

            //使用链式编程的方式进行设置
            bootstrap.group(boosGroup, wokerGroup)//设置两个线程组
                    .channel(NioServerSocketChannel.class)//使用NioSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列得到连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //创建一个通道初始化对象，给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //System.out.println("客户socketchannel hashcode=" + ch.hashCode());
                            //可以使用一个集合管理SocketChannel，在推送消息时，可以将业务加入到各个channel对应的NIOEventLoop的taskQueue
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ReadTimeoutHandler(60*30));
                            pipeline.addLast(new NettyServerHandler());

                        }
                    });//给workerGroup的EventGroup对应的管道设置处理器
            logger.info("服务器 is ready。。。。。");
            //绑定一个端口并且同步，生成一个channelFuture对象
            //这里已经启动了服务器
            ChannelFuture cf = bootstrap.bind(7777).sync();
            //给cf注册监听器。监控我们关心的事件
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            boosGroup.shutdownGracefully();
            wokerGroup.shutdownGracefully();
        }
    }
}

